package tw.cuttle.entry;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;

import tw.cuttle.ActionContext;
import tw.cuttle.ActionHelper;
import tw.cuttle.CuttleContext;
import tw.cuttle.bean.Action;
import tw.cuttle.bean.Actions;
import tw.cuttle.bean.Form;
import tw.cuttle.bean.Process;
import tw.cuttle.bean.Resource;
import tw.cuttle.bean.Setting;
import tw.cuttle.core.CuttleConfigurationParser;
import tw.cuttle.view.parameter.ParameterDigester;

public class EntryHelper {
    private Log LOGGER=LogFactory.getLog(EntryHelper.class);
    private String PARAM_AJAXREQUEST="P_AJAXREQ";
    private String surfix;
    private ServletContext servletContext;
    /**
     * @return the servletContext
     */
    public ServletContext getServletContext() {
        return servletContext;
    }
    /**
     * @param servletContext the servletContext to set
     */
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }
    /**
     * @return the surfix
     */
    public String getSurfix() {
        return surfix;
    }
    /**
     * @param surfix the surfix to set
     */
    public void setSurfix(String surfix) {
        this.surfix = surfix;
    }
    public String getActionId(HttpServletRequest request){
	    String contentPath=request.getContextPath();
		String URI=request.getRequestURI().toString();
		String actionId=null;
		if(URI.lastIndexOf('.')>0){
			actionId=URI.substring(contentPath.length()+1, URI.lastIndexOf('.'));
			if(surfix==null)setSurfix(URI.substring(URI.lastIndexOf('.')+1));
		}else{
			actionId=URI.substring(contentPath.length()+1, URI.length());
		}
		LOGGER.info("executedActionId:"+actionId);
		return actionId;
	}
    public Boolean isAjaxRequest(HttpServletRequest request){
	    boolean isAjaxReq=false;
		String P_AJAXREQ=request.getParameter(PARAM_AJAXREQUEST);
		if(P_AJAXREQ!=null){
		    isAjaxReq=Boolean.valueOf(P_AJAXREQ);
		}
		return isAjaxReq;
	}
    public void initActionContext(ServletRequest request, ServletResponse response){
	    ActionContext actionContext=new ActionContext();
	    ActionHelper helper=null;
	    if(CuttleContext.getBeanHolder().getSetting().getEnv().getHelper().equals(ActionHelper.class.getName())){
		helper=new ActionHelper();
	    }else{
		try {
		    helper=(ActionHelper) Class.forName(CuttleContext.getBeanHolder().getSetting().getEnv().getHelper()).newInstance();
		} catch(Exception e) {
		    e.printStackTrace();
		    throw new RuntimeException(e);
		}
	    }
	    //add current Action
	    Action executedAction=CuttleContext.getBeanHolder().getAction(getActionId((HttpServletRequest)request));
	    helper.getExecutedActions().add(executedAction);
	    helper.setRequest((HttpServletRequest)request);
	    helper.setResponse((HttpServletResponse)response);
	    helper.setContext(servletContext);
	    helper.setIsAjaxRequest(isAjaxRequest((HttpServletRequest)request));
	    actionContext.setActionHelper(helper);
	    actionContext.setAccessTime(new Date().getTime());
	    CuttleContext.setActionContext(actionContext);
	    /*
	     * set form
	     */
	    if(helper.getCurrentAction().getForm()!=null){
		if(CuttleContext.getBeanHolder().getForm(helper.getCurrentAction().getForm()).getType().equals(Form.FORM_TYPE.DYNA.name())){
		    helper.setForm(ParameterDigester.parse());
		}else{
		    try {
			helper.setForm(ParameterDigester
			    .parse(Class.forName(CuttleContext.getBeanHolder().getForm(helper.getCurrentAction().getForm()).get_class())));
		    } catch (Exception e){
		    	e.printStackTrace();
			throw new RuntimeException(e);
		    }
		}
	    }

	}
    public void execute(HttpServletRequest request, HttpServletResponse response){
		CuttleContext.setServletContext(this.getServletContext());
		this.initActionContext(request, response);
		
		
		String actionId=this.getActionId(request);
		if(this.isAjaxRequest(request)){
		    CuttleContext.getActionHandler().ajaxRequest(actionId);
		}else{
		    CuttleContext.getActionHandler().request(actionId);
		}
    }
    public void execute(String providedActionId, HttpServletRequest request, HttpServletResponse response){
		CuttleContext.setServletContext(this.getServletContext());
		this.initActionContext(request, response);
		String actionId=providedActionId;
		
		Action action=CuttleContext.getBeanHolder().getAction(actionId);
		action.getPreExec();
		//CuttleContext.getActionContext().exec
		
		if(this.isAjaxRequest(request)){
		    CuttleContext.getActionHandler().ajaxRequest(actionId);
		}else{
		    CuttleContext.getActionHandler().request(actionId);
		}
    }
    public void init(ServletContext servletContext) {
	    try {
			this.setServletContext(servletContext);
			CuttleContext.setServletContext(servletContext);
			Setting setting=CuttleContext.getBeanHolder().getSetting();
			//form
			if(setting!=null && setting.getForms()!=null && setting.getForms().getFormList()!=null){
			    	CuttleContext.getBeanHolder().setFormMap(new HashMap<String, Form>());
    			for(int i=0;i<setting.getForms().getFormList().size();i++){
    			    Form form=setting.getForms().getFormList().get(i);
    			    CuttleContext.getBeanHolder().getFormMap().put(form.getName(), form);
    			}
			}
			Actions actions=new Actions();
			actions.setActions(new ArrayList<Action>());
			if(CuttleContext.getBeanHolder().getActions()!=null){
			    actions.getActions().addAll(CuttleContext.getBeanHolder().getActions().getActions());
			}
			if(setting!=null && setting.getResources()!=null && setting.getResources().getResourceList()!=null)
			for(Resource resource:setting.getResources().getResourceList()){
			    LOGGER.debug("resource path:"+resource.getPath());
    			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    			DocumentBuilder db = dbf.newDocumentBuilder();
    			Document doc = db.parse(servletContext.getResourceAsStream(resource.getPath()));
			    actions.getActions().addAll(CuttleConfigurationParser.parseAction(doc).getActions());
			}
			//Action Map, Process Map
			Map<String, Action> actionMap=new HashMap<String, Action>();
			Map<String, Process> processMap=new HashMap<String, Process>();
			Map<String, List<Process>> processListMap=new HashMap<String, List<Process>>();
			for(int i=0;i<actions.getActions().size();i++){
			    Action action=actions.getActions().get(i);
			    actionMap.put(action.getId(), action);
			}
			
			CuttleContext.getBeanHolder().setActionMap(actionMap);
			for(int i=0;i<actions.getActions().size();i++){
			    Action action=actions.getActions().get(i);
			    List<Process> processList=new ArrayList<Process>();
			    evaluateExtendProcesses(action, processList);
			    Integer processSize=processList.size()-1;
			    for(int j=0;j<=processSize;j++){
				processMap.put(action.getId()+"-"+processList.get(processSize-j).getId(), processList.get(processSize-j));
			    }
			}
			CuttleContext.getBeanHolder().setProcessMap(processMap);
			
			
			CuttleContext.getBeanHolder().setActions(actions);
			
			for(int i=0;i<actions.getActions().size();i++){
			    List<Process> ajaxExtendProcessList=new ArrayList<Process>();
			    evaluateAjaxExtendProcesses(actions.getActions().get(i), ajaxExtendProcessList);
			    List<Process> straightAjaxExtendProcessList=new ArrayList<Process>();
			    int ajaxExtendSize=ajaxExtendProcessList.size()-1;
			    for(int j=0;j<=ajaxExtendSize;j++){
				straightAjaxExtendProcessList.add(ajaxExtendProcessList.get(ajaxExtendSize-j));
			    }
			    processListMap.put(actions.getActions().get(i).getId()+"_ajax", straightAjaxExtendProcessList);
			    
			    List<Process> straightExtendProcessList=new ArrayList<Process>();
			    List<Process> extendProcessList=new ArrayList<Process>();
			    evaluateExtendProcesses(actions.getActions().get(i), extendProcessList);
			    int extendSize=extendProcessList.size()-1;
			    for(int j=0;j<=extendSize;j++){

				straightExtendProcessList.add(extendProcessList.get(extendSize-j));
			    }
			    processListMap.put(actions.getActions().get(i).getId(), straightExtendProcessList);
			    
			}
			CuttleContext.getBeanHolder().setProcessListMap(processListMap);
			
	    } catch (Exception e) {
		e.printStackTrace();
		throw new RuntimeException(e);
		
	    }
	    	
	}
	private void evaluateExtendProcesses(Action action, List<Process> processList){
	    evaluateAjaxExtendProcesses(action, processList);
	    if(action.getExtend()!=null && action.getExtend().length()>0){
		String actionIds[]=action.getExtend().split(",");
		int size=actionIds.length-1;
		for(int k=0;k<=size;k++){
		    evaluateExtendProcesses(CuttleContext.getBeanHolder().getAction(actionIds[size-k]), processList);
		}
	    }
	    
	    
	}
	private void evaluateAjaxExtendProcesses(Action action, List<Process> processList){
	    if(action.getProcesses()!=null){
		
		int size=action.getProcesses().size()-1;
		for(int k=0;k<=size;k++){
		    Boolean isExist=false;
		    if(processList!=null)
		    for(Process process:processList){
			if(process.equals(action.getProcesses().get(size-k))){
			   isExist=true; 
			   break;
			}
		    }
		    if(!isExist){
			processList.add(action.getProcesses().get(size-k));
		    }
		}
	    }
	    if(action.getAjaxExtend()!=null && action.getAjaxExtend().length()>0){
		String actionIds[]=action.getAjaxExtend().split(",");
		int size=actionIds.length-1;
		for(int k=0; k<=size ;k++){
		    evaluateAjaxExtendProcesses(CuttleContext.getBeanHolder().getAction(actionIds[size-k]), processList);
		}
	    }
	    
	}
}
